package org.hong.monkey.deploy.master.ui

import org.hong.monkey.Logging
import org.hong.monkey.deploy.master.Master
import org.hong.monkey.status.api.v1.{ApiRootResource, ApplicationsListResource, ApplicationInfo,
  UIRoot}
import org.hong.monkey.ui.{MonkeyUI, WebUI}
import org.hong.monkey.ui.JettyUtils._

/**
 * Web UI server for the standalone master.
 */
private[master]
class MasterWebUI(
    val master: Master,
    requestedPort: Int,
    customMasterPage: Option[MasterPage] = None)
  extends WebUI(requestedPort, master.conf, name = "MasterUI") with Logging
  with UIRoot {

  val masterEndpointRef = master.self
  val killEnabled = master.conf.getBoolean("monkey.ui.killEnabled", true)

  val masterPage = customMasterPage.getOrElse(new MasterPage(this))

  initialize()

  /** Initialize all components of the server. */
  def initialize() {
    val masterPage = new MasterPage(this)
    attachPage(new ApplicationPage(this))
    attachPage(new HistoryNotFoundPage(this))
    attachPage(masterPage)
    attachHandler(createStaticHandler(MasterWebUI.STATIC_RESOURCE_DIR, "/static"))
    attachHandler(ApiRootResource.getServletHandler(this))
    attachHandler(createRedirectHandler(
      "/app/kill", "/", masterPage.handleAppKillRequest, httpMethods = Set("POST")))
    attachHandler(createRedirectHandler(
      "/driver/kill", "/", masterPage.handleDriverKillRequest, httpMethods = Set("POST")))
  }

  /** Attach a reconstructed UI to this Master UI. Only valid after bind(). */
  def attachMonkeyUI(ui: MonkeyUI) {
    assert(serverInfo.isDefined, "Master UI must be bound to a server before attaching MonkeyUIs")
    ui.getHandlers.foreach(attachHandler)
  }

  /** Detach a reconstructed UI from this Master UI. Only valid after bind(). */
  def detachMonkeyUI(ui: MonkeyUI) {
    assert(serverInfo.isDefined, "Master UI must be bound to a server before detaching MonkeyUIs")
    ui.getHandlers.foreach(detachHandler)
  }

  def getApplicationInfoList: Iterator[ApplicationInfo] = {
    val state = masterPage.getMasterState
    val activeApps = state.activeApps.sortBy(_.startTime).reverse
    val completedApps = state.completedApps.sortBy(_.endTime).reverse
    activeApps.iterator.map { ApplicationsListResource.convertApplicationInfo(_, false) } ++
      completedApps.iterator.map { ApplicationsListResource.convertApplicationInfo(_, true) }
  }

  def getMonkeyUI(appId: String): Option[MonkeyUI] = {
    val state = masterPage.getMasterState
    val activeApps = state.activeApps.sortBy(_.startTime).reverse
    val completedApps = state.completedApps.sortBy(_.endTime).reverse
    (activeApps ++ completedApps).find { _.id == appId }.flatMap {
      master.rebuildMonkeyUI
    }
  }
}

private[master] object MasterWebUI {
  private val STATIC_RESOURCE_DIR = MonkeyUI.STATIC_RESOURCE_DIR
}
